Skip to content

feat(login): username/password + host:port credentials sign-in alongside SSO#16

Merged
BorisTyshkevich merged 1 commit into
mainfrom
feat/credentials-login
Jun 22, 2026
Merged

feat(login): username/password + host:port credentials sign-in alongside SSO#16
BorisTyshkevich merged 1 commit into
mainfrom
feat/credentials-login

Conversation

@BorisTyshkevich

Copy link
Copy Markdown
Collaborator

What

Adds a second sign-in path to the login screen: ClickHouse username + password (HTTP Basic), optionally against another host:port, as an alternative to the existing OAuth/SSO flow. Faithfully recreates the handoff Login.html design in vanilla h(), reusing the app's existing tokens (Altinity-blue accent, no dev-only Tweaks panel).

Why

Many ClickHouse deployments have no OAuth — just a CH user + password. This lets those users sign in, and lets anyone point the credential path at a different server.

How

  • src/ui/login.js — rebuilt: SSO + credentials with a primary/secondary button swap (Connect becomes primary once both fields are filled), an Advanced host disclosure, password show/hide, and a live Target summary row.
  • src/ui/app.jsauthMode (oauth | basic); a connect() action that probes SELECT 1, commits the session, and enters the workbench; basic-mode branches behind the existing chCtx seams (getToken/authHeader/refresh/isSignedIn/email/host), ensureConfig no-op, clearTokens reset. A basic session is restored from ch_basic_* sessionStorage. No ch-client.js changes — the seams were already there.
  • src/core/target.js — pure resolveTarget() host→origin normalizer (blank → serving origin; bare host → https://…:8443; explicit scheme/port honoured).
  • src/net/oauth-config.js — parse top-level basic_login (default on; set false to force SSO-only); tolerate 0 IdPs (credentials-only deployments).
  • src/main.js — bootstrap decision → app.isSignedIn() (covers both modes).
  • docsdeploy/config.json.example basic_login; README credentials section incl. the CSP connect-src + target CORS caveats for cross-origin hosts.

Security notes

  • Password held in sessionStorage for the tab session (same lifetime as the OAuth token), sent as Authorization: Basic base64(user:password).
  • Same-origin credentials need no extra setup. A cross-origin host requires both (a) adding the origin to the SPA's connect-src CSP and (b) the target CH allowing CORS / answering the Authorization preflight — documented in the README.

Tests

  • npm test: 452 passing, 100% per-file coverage gate green (app.js 100/90.81/96.73/100).
  • npm run build: clean → dist/sql.html.
  • New/updated specs: target.test.js, login.test.js (full rewrite), app.test.js (basic-mode suite), oauth-config.test.js, main.test.js.

E2E (pending, delegated)

To be verified on the github demo cluster (id 337, CH 26.3.10.62) with demo:demodemo:demo auth already confirmed via ACM. Primary case is same-origin credentials (no CORS). Deploy is clickhouse-clientuser_files/sql.html (overwrites the live asset — confirm before deploying).

🤖 Generated with Claude Code

…side SSO

Adds a second sign-in path to the login screen: HTTP Basic credentials
(ClickHouse user + password), optionally against another host:port, as an
alternative to the OAuth/SSO flow.

- src/ui/login.js: rebuilt to the Login.html design — SSO + credentials with a
  primary/secondary swap, an "Advanced" host disclosure, password show/hide, and
  a live "Target" summary row. Faithful to the handoff, reusing existing tokens.
- src/ui/app.js: `authMode` ('oauth' | 'basic'); a `connect()` action that probes
  SELECT 1, commits the session, and enters the workbench; basic branches behind
  the existing chCtx seams (getToken/authHeader/refresh/isSignedIn/email/host),
  ensureConfig no-op, clearTokens resets. Basic session restored from
  sessionStorage (ch_basic_*); no ch-client changes needed.
- src/core/target.js: pure resolveTarget() host→origin normalizer.
- src/net/oauth-config.js: parse top-level `basic_login` (default on), tolerate
  0 IdPs (credentials-only deployments).
- src/main.js: bootstrap decision → app.isSignedIn() (covers both modes).
- docs: config.json.example `basic_login`; README credentials section incl. the
  CSP connect-src + target CORS caveats for cross-origin hosts.

Tests at 100% per-file gate (452 passing); build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WFt3fLEJW7XdBhoc8SgH9A
@BorisTyshkevich

Copy link
Copy Markdown
Collaborator Author

E2E verified on the github demo cluster (demo:demo) ✅

Deployed this branch's dist/sql.html to github.demo.altinity.cloud (user_files/github-play-sql.html, upload-only — no restart), then drove the credentials path in a real browser.

Cluster: OSS ClickHouse 26.3.10.62 behind the ch-jwt-verify sidecar (Basic-auth mode); config served inline as ch_auth:basic, Auth0 SSO + basic_login default-on.

Results — same-origin credentials (primary case, no CORS):

  • New two-path login renders per Login.html: SSO button + credentials, Advanced host disclosure, password show/hide, and the live Target row.
  • Entering demo / demo flips Target via SSO → as demo and promotes Connect to primary (the primary/secondary swap works).
  • Connect → signed in. Basic base64(demo:demo) is accepted same-origin — the ch-jwt-verify front door passes real ClickHouse credentials through to CH (a real demo CH user exists on this cluster).
  • Query runs as that user: SELECT currentUser(), version()demo / 26.3.10.62; header shows demo.
  • Logout clears the ch_basic_* sessionStorage and returns to the login screen with the credentials UI restored.
  • The existing SSO path is untouched (still rendered and working).

No bugs found. npm test green locally (452 passing, per-file gate intact; app.js 100/90.81/96.73/100).

Note: github.demo currently runs this PR build (the live asset was overwritten for the test); merging reconciles it.

@BorisTyshkevich BorisTyshkevich merged commit 0da0c0d into main Jun 22, 2026
2 checks passed
@BorisTyshkevich BorisTyshkevich deleted the feat/credentials-login branch June 22, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant